/**以下类适用于
 * 服务器不断实时推送，
 * 数据逐渐增加的长列表优化，
 * 回调中的list可用于渲染，
 * 节省渲染dom数。
 * */

/**
 * @export class
 * @class 长列表数据渲染限频
 */
class TaskList {
  constructor(callback) {
    this.callback = callback;

    this.list = [];
    this.timeout = null;
    // 最多缓存待渲染的消息条数
    this.catchMax = 1000;

    // 每次渲染条数 [min, max] 取闭区间
    this.renderOnceNumber = [1, 3];
    // 每次渲染相隔时间 [min, max] 取闭区间 , 单位ms
    this.renderOnceTimeout = [100, 800];
  }

  // 实时消息调用入口
  push(msg) {
    if (!msg) return console.warn("消息为空.", msg);

    this.list.push(msg);

    // 如果消息堆积达到上限，丢掉待渲染的 10分之1 消息（例如1000条，则丢掉待渲染的前100条。）
    if (this.list.length > this.catchMax) {
      this.list.splice(0, Math.ceil(this.catchMax / 10));
    }

    // 如果未启动渲染，则启动
    if (this.timeout === null) this.start();
  }

  start() {
    // 启动渲染定时器，并赋值，方便在push时判断是否需要，即刻启动渲染。
    this.timeout = setTimeout(async () => {
      if (typeof this.callback === "function") {
        try {
          this.callback(
            this.list.splice(0, this.getRandom(this.renderOnceNumber))
          );
        } catch (e) {
          console.error(e);
        }
      }
      // 如果待渲染消息没有了，则退出
      if (this.list.length <= 0) {
        clearTimeout(this.timeout);
        this.timeout = null;
        return;
      }
      await Promise.resolve();
      // 继续调用渲染
      this.start();
    }, this.getRandom(this.renderOnceTimeout));
  }

  getRandom([min, max]) {
    const diff = Math.floor(max - min);
    return +(Math.random() * diff).toFixed(0) + min;
  }

  // 结束直播后，建议调用此方法。渲染最后的50条消息（防止消息堆积， 列表渲染结束时间过长）
  endLive(number = 50) {
    this.list = this.list.splice(-number);
    // 清除本地模拟的数据循环定时器
    this.testInterval && clearInterval(this.testInterval);
  }
}
